/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   15-2-3 下午3:33 Created by dwzhang
 */
package com.jade.bss.web.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.CriterionUtils;
import com.jade.framework.base.criterion.MatchMode;
import com.jade.framework.base.criterion.Restrictions;
import com.jade.framework.base.util.PagingList;
import com.jade.framework.base.util.PagingResult;
import com.jade.framework.base.util.ResponseUtils;
import com.jade.modules.region.Region;
import com.jade.modules.region.RegionException;
import com.jade.modules.region.RegionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * 地区管理的控制器接口.
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a>
 * @version 1.0 15-2-3 下午3:33
 */
@RestController
@RequestMapping (value = "/region", produces = MediaType.APPLICATION_JSON_VALUE)
@Api(value = "地区管理", description = "地区管理")
public class RegionController
{
    @Autowired
    private MessageSource messageSource;
    private Log log = LogFactory.getLog(RegionController.class);
   
    @RequiresAuthentication
    @RequestMapping (value = "/get/{id}", method = RequestMethod.GET)
    @ApiOperation(value = "地区id", httpMethod = "GET")
    public void get(@ApiParam(value = "地区标识") @PathVariable String id,HttpServletResponse response)
            throws Exception
    {
        Region region = RegionUtils.getRegion(id);
        Region parentRegion = RegionUtils.getRegion(region.getParentId());
        if(parentRegion!=null)
            region.setParent(parentRegion);
        ResponseUtils.writeSuccessResult(response,region);
    }

   
    @RequiresAuthentication
    @RequiresPermissions (value = {"region:add"})
    @RequestMapping (value = "/add", method = RequestMethod.POST)
    @ApiOperation(value = "增加地区", httpMethod = "POST")
    public void addRegion(@ApiParam("地区标识") @RequestParam (value = "parentId", required = false) String parentId,
                          @ApiParam("地区对象") @RequestBody Region region, HttpServletResponse response)
            throws Exception
    {
        if (StringUtils.isNotBlank(parentId)) {
            region.setParentId(parentId);
        }
        RegionUtils.addRegion(region);
        ResponseUtils.writeSuccessResult(response);
    }

   
    @RequestMapping (value = "/query", method = RequestMethod.GET)
    @ApiOperation(value = "查询地区列表", httpMethod = "GET")
    public void queryRegion(@ApiParam(value = "地区标识") @RequestParam (value = "parentId", required = false) String parentId,
                            @ApiParam(value = "关键词") @RequestParam (value = "keyword", required = false) String key,
                            @ApiParam(value = "是否递归") @RequestParam (value = "recursive ", required = false) boolean recursive,
                            @ApiParam(value = "是否全名") @RequestParam (value = "fullname", defaultValue = "false") boolean fullname,
                            @ApiParam(value = "起始值") @RequestParam (value = "offset",defaultValue = "0") int offset,
                            @ApiParam(value = "每页大小") @RequestParam (value = "length", defaultValue = "10") int length,
                            @ApiParam(value = "排序字段") @RequestParam (value = "sort", required = false) String sortName,
                            @ApiParam(value = "排序规则", allowableValues = "desc, asc") @RequestParam (value = "order", required = false, defaultValue = "asc") String sortType,
                            HttpServletResponse response) throws Exception
    {
        Criteria criteria = new Criteria(offset, length);
        if (StringUtils.isNotBlank(parentId)) {
            if (recursive) {
                List<String> ids = RegionUtils.getSubIds(parentId);
                ids.add(parentId);
                criteria.add(Restrictions.in("id", ids));
            }
            else {
                criteria.add(Restrictions.eq("parentId", parentId));
            }
        }
        if (StringUtils.isNotBlank(key)) {
            key = key.toLowerCase();
            criteria.add(
                    Restrictions.or(Restrictions.like("id", key), Restrictions.like("cnName", key),
                            Restrictions.like("enName", key, MatchMode.START),
                            Restrictions.like("code", key), Restrictions.like("fullSpell", key, MatchMode.START),
                            Restrictions.like("firstSpell", key, MatchMode.START)));
        }
        CriterionUtils.addOrder(criteria, sortName, sortType, "id");

        PagingList<Region> regions = RegionUtils.queryRegion(criteria);

        if (fullname) {
            for (Region region : regions) {
                region.setCnName(StringUtils.join(RegionUtils.getNames(region.getId()), '-'));
            }
        }
        PagingResult result = PagingResult.getResult(regions);
        ResponseUtils.writeSuccessResult(response, result);
//        return ControllerUtils.getAjaxResult(regions, new Region[regions.size()], null);
    }

   
    @RequiresAuthentication
    @RequiresPermissions (value = {"region:remove"})
    @RequestMapping (value = "/remove", method = RequestMethod.DELETE)
    @ApiOperation(value = "删除地区", httpMethod = "DELETE")
    public void removeRegion(@ApiParam(value = "地区标识") @RequestParam ("id") String[] ids, HttpServletResponse response)
            throws Exception
    {
        RegionUtils.removeRegion(ids);
        ResponseUtils.writeSuccessResult(response);
    }

   
    @RequiresAuthentication
    @RequiresPermissions (value = {"region:edit"})
    @RequestMapping (value = "/edit", method = RequestMethod.PUT)
    @ApiOperation(value = "编辑地区", httpMethod = "PUT")
    public void editRegion(@ApiParam(value = "地区对象") @RequestBody Region region, HttpServletResponse response)
            throws Exception
    {
        RegionUtils.updateRegion(region);
        ResponseUtils.writeSuccessResult(response);
    }

    @RequiresAuthentication
    @RequiresPermissions (value = {"region:add"})
    @RequestMapping (value = "/importRegion.do", method = RequestMethod.POST)
    @ApiOperation(value = "导入地区", httpMethod = "POST")
    public void importRegion(@ApiParam(value = "地区文件") @RequestParam (value = "region_file", required = false) MultipartFile file,
                             HttpServletResponse response)
            throws Exception
    {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (!StringUtils.equalsIgnoreCase(extension, "xls") && !StringUtils.equalsIgnoreCase(extension, "xlsx")) {
            throw new RegionException("err.module.region.import_file_format", "invalid file format");
        }
        if (file.getSize() > 5 * org.apache.commons.io.FileUtils.ONE_MB) {
            throw new RegionException("err.module.region.import_file_big", "max file size");
        }

        Workbook wb = null;
        if (StringUtils.equalsIgnoreCase(extension, "xls")) {
            wb = new HSSFWorkbook(file.getInputStream());
        }
        else {
            wb = new XSSFWorkbook(file.getInputStream());
        }
        int addCount = 0;
        int updateCount = 0;
        int failCount = 0;
        int sheetCount = wb.getNumberOfSheets();
        for (int i = 0; i < sheetCount; i++) {
            Sheet sheet = wb.getSheetAt(i);
            if (sheet == null) {
                continue;
            }
            int rowCount = sheet.getLastRowNum() + 1;
            //ignore header line
            for (int j = 1; j < rowCount; j++) {
                Row row = sheet.getRow(j);
                if (row == null) {
                    continue;
                }
                int k = 0;
                Region region = new Region();
                Cell cell = row.getCell(k++);
                //region.setUniCode(getStringCellValue(cell));
                //cell = row.getCell(k++);
                region.setId(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setParentId(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setCnName(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setAbbrCnName(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setEnName(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setCode(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setZipcode(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setFullSpell(getStringCellValue(cell));
                cell = row.getCell(k++);
                region.setFirstSpell(getStringCellValue(cell));
                if (StringUtils.isBlank(region.getId()) || StringUtils.isBlank(region.getCnName())) {
                    log.warn("No id or name data found for row " + j);
                    failCount++;
                    continue;
                }

                try {
                    if (RegionUtils.getRegion(region.getId()) != null) {
                        if (log.isDebugEnabled()) {
                            log.debug("Update region " + region.getId());
                        }
                        RegionUtils.updateRegion(region);
                        updateCount++;
                    }
                    else {
                        if (log.isDebugEnabled()) {
                            log.debug("Add region " + region.getId());
                        }
                        RegionUtils.addRegion(region);
                        addCount++;
                    }
                }
                catch (Throwable t) {
                    log.warn("Can't import region for row " + j, t);
                    failCount++;
                }
            }
        }
        String result = "{\"status\":\"200\",\"addCount\":\"" + addCount + "\",\"updateCount\":\" " + updateCount +
                "\",\"failCount\":\" " + failCount + "\"}";
        response.getWriter().write(result);
    }

    protected String getStringCellValue(Cell cell)
    {
        return cell == null ? null : cell.getStringCellValue();
    }

//    @RequestMapping (value = "/exportRegion.do", method = RequestMethod.GET)
//   //    @CheckPermission (permission = {PER_VIEW_REGION, PER_EDIT_REGION}, mode = MODE_OR)
//    public void exportRegion(@RequestParam (value = "parentId", required = false) String parentId,
//                             @RequestParam (value = "key", required = false) String key, HttpServletRequest request,
//                             HttpServletResponse response)
//            throws Exception
//    {
//        int offset = 1;
//        int length = 1000;
//        PagingList<Region> regions = RegionUtils.queryRegion(parentId, level, key, 0, length, false);
//        OutputStream out = response.getOutputStream();
//        try {
//            // keep 100 rows in memory, exceeding rows will be flushed to disk
//            SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//            Sheet sh = wb.createSheet();
//            int count = regions.getTotalCount();
//            int i = writeHeader(sh, request);
//            while (count >= 0) {
//                for (Region region : regions) {
//                    Row row = sh.createRow(i++);
//                    int j = 0;
//                    Cell cell = row.createCell(j++);
//                    //String address = new CellReference(cell).formatAsString();
//                    cell.setCellValue(region.getUniCode());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getId());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getCnName());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getAbbrCnName());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getEnName());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getCode());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getZipcode());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getFullSpell());
//                    cell = row.createCell(j++);
//                    cell.setCellValue(region.getFirstSpell());
//                }
//                int size = regions.size();
//                if (size < length) {
//                    break;
//                }
//                count -= size;
//                offset += 1;
//                regions = regionManager.queryRegion(parentId, level, key, (offset - 1) * length, length, false);
//            }
//            response.setContentType("application/vnd.ms-excel.12;charset=gb2312");
//            response.addHeader("Content-Disposition", "attachment;filename=region.xlsx");
//            wb.write(response.getOutputStream());
//            wb.dispose();
//        }
//        catch (Exception e) {
//            JadeSystem.getLogger().warn("Can't export region:", e);
//            throw e;
//        }
//        finally {
//            IOUtils.closeQuietly(out);
//        }
//    }
//
//    protected int writeHeader(Sheet sheet, HttpServletRequest request)
//    {
//        Locale locale = new Locale("zh", "CN");
//        String locales = (String) request.getSession().getAttribute("locale");
//        if (StringUtils.isNotBlank(locales)) {
//            locales = request.getLocale().toString();
//        }
//        if (StringUtils.isNotBlank(locales) && locales.contains("_")) {
//            locale = new Locale(locales.split("_")[0], locales.split("_")[1]);
//        }
//
//        String header = messageSource.getMessage("inf.jade.bss.region.export_title", null, locale);
//        if (StringUtils.isBlank(header)) {
//            return 0;
//        }
//        String[] headerArray = header.split(",");
//        Row headRow = sheet.createRow(0);
//        if (headerArray.length >= 9) {
//            for (int i = 0; i < 9; i++) {
//                Cell cell = headRow.createCell(i);
//                cell.setCellValue(headerArray[i]);
//            }
//            return 1;
//        }
//        else {
//            return 0;
//        }
//    }

   
    @RequestMapping (value = "/getRegionByName.do", method = RequestMethod.GET)
    @ApiOperation(value = "根据地区名查地区", httpMethod = "GET")
    public void getRegionByName(@ApiParam(value = "地区名称") @RequestParam (value = "names") String[] names,
                                @ApiParam(value = "地区类型") @RequestParam (value = "type") String type,
                                HttpServletResponse response) throws Exception
    {
        ResponseUtils.writeSuccessResult(response, RegionUtils.getRegionByName(names, type));
    }

   
    @RequestMapping (value = "/listSubRegion.do", method = RequestMethod.GET)
    @ApiOperation(value = "查询父地区", httpMethod = "GET")
    public void listSubRegion(@ApiParam(value = "地区标识") @RequestParam (value = "parentId", required = false) String parentId, HttpServletResponse response) throws Exception
    {
        ResponseUtils.writeSuccessResult(response, RegionUtils.listRegion(parentId));
    }

   
    @RequestMapping (value = "/getRegionName.do", method = RequestMethod.GET)
    @ApiOperation(value = "查询地区全名", httpMethod = "GET")
    public void getRegionName(@ApiParam(value = "地区标识") @RequestParam (value = "regionId", required = true) String[] regionIds,
                              @ApiParam(value = "地区全名") @RequestParam (value = "fullname", defaultValue = "true") boolean fullname,
                              @ApiParam(value = "是否中文地区") @RequestParam (value = "ignoreCn", defaultValue = "true") boolean ignoreCn,
                              @ApiParam(value = "是否简称") @RequestParam (value = "abbr", defaultValue = "true") boolean abbr,
                              @ApiParam(value = "连接符") @RequestParam (value = "nameSep", defaultValue = "-") String nameSep, HttpServletResponse response)
            throws Exception
    {
        Map<String, String> nameMap = new HashMap<String, String>();
        for (String regionId : regionIds) {
            if (!fullname) {
                nameMap.put(regionId, RegionUtils.getName(regionId, abbr));
            }
            else {
                String[] array = RegionUtils.getNames(regionId, abbr);
                if (regionId.startsWith("cn") && ignoreCn) {
                    nameMap.put(regionId, StringUtils.join(array, nameSep, 1, array.length));
                }
                else {
                    nameMap.put(regionId, StringUtils.join(array, nameSep));
                }
            }
        }
        ResponseUtils.writeSuccessResult(response, nameMap);
    }
}
